import COS, {
  type TaskId,
  type ProgressInfo,
  type UploadFileResult,
} from 'cos-js-sdk-v5';
import { nanoid } from 'nanoid';
import type { CredentialData } from 'qcloud-cos-sts';
import { result } from './utils';

export const genProductImageKey = (userId: string) =>
  `${userId}/image/product/${nanoid()}`;

export const genShopImageKey = (userId: string) =>
  `${userId}/image/shop/${nanoid()}`;

export const genQualificationImageKey = (userId: string) =>
  `${userId}/image/shop/qualification/${nanoid()}`;

export const genUserAvatarKey = (userId: string) =>
  `${userId}/image/avatar/${nanoid()}`;

export const getTempCredential = async () => {
  try {
    const res = await fetch('/api/cos-sts');
    const data: CredentialData = await res.json();
    return result(data);
  } catch (error: unknown) {
    return result(error, '获取临时凭证失败');
  }
};

export class CosClient {
  client: COS;
  private bucket: string;
  private region: string;
  constructor({ bucket, region }: { bucket: string; region: string }) {
    this.bucket = bucket;
    this.region = region;
    this.client = new COS({
      getAuthorization: async (_, callback) => {
        const { result: data, error } = await getTempCredential();
        if (error) throw new Error(error.message);
        callback({
          TmpSecretId: data.credentials.tmpSecretId,
          TmpSecretKey: data.credentials.tmpSecretKey,
          SecurityToken: data.credentials.sessionToken,
          StartTime: data.startTime, // 时间戳，单位秒，如：1580000000
          ExpiredTime: data.expiredTime, // 时间戳，单位秒，如：1580000000
          ScopeLimit: true, // 细粒度控制权限需要设为 true，会限制密钥只在相同请求时重复使用
        });
      },
    });
  }
  upload({
    key,
    file,
    onProgress,
    onTaskReady,
  }: {
    key: string;
    file: File;
    onProgress?: (p: ProgressInfo) => unknown;
    onTaskReady?: (id: TaskId) => unknown;
  }) {
    const promise = new Promise<UploadFileResult>((resolve, reject) => {
      this.client.uploadFile(
        {
          Bucket: this.bucket,
          Region: this.region,
          Key: key,
          Body: file,
          SliceSize: 1024 * 1024 * 10,
          onProgress,
          onTaskReady,
        },
        (err, data) => (err ? reject(err) : resolve(data)),
      );
    });
    return promise;
  }
  getObjectUrl(key: string, expires = 900) {
    return new Promise<string>((resolve, reject) => {
      this.client.getObjectUrl(
        {
          Bucket: this.bucket,
          Region: this.region,
          Key: key,
          Sign: true,
          Expires: expires,
          Protocol: 'https:',
        },
        (err, data) => {
          if (err) return reject(err);
          const url = new URL(data.Url);
          url.searchParams.set('response-content-disposition', 'inline');
          resolve(url.toString());
        },
      );
    });
  }
  delete(keys: string[]) {
    return new Promise((resolve, reject) => {
      this.client.deleteMultipleObject(
        {
          Bucket: this.bucket,
          Region: this.region,
          Objects: keys.map((key) => ({ Key: key })),
        },
        (err, data) => (err ? reject(err) : resolve(data)),
      );
    });
  }
}
